package uk.ac.lkl.common.util.ds;



import java.util.ArrayList;
import java.util.HashMap;

import uk.ac.lkl.common.util.ds.event.MapEvent;
import uk.ac.lkl.common.util.ds.event.MapListener;


/**
 * Wraps up a map so that can see additions/removals and value changes.
 * 
 * @author Darren Pearce
 * @version $Revision$
 * @version $Date$
 * 
 */
public class NotifyingMap<K, V> extends HashMap<K, V> {
	private static final long serialVersionUID = 1L;

    private ArrayList<MapListener<K, V>> listeners;


    public NotifyingMap() {
        super();
        listeners = new ArrayList<MapListener<K, V>>();
    }


    @Override
    public V put(K key, V value) {
        boolean update = containsKey(key);
        V oldValue = super.put(key, value);
        if (update)
            fireValueChanged(key, oldValue, value);
        else
            fireEntryAdded(key, value);
        return oldValue;
    }


    @Override
    public V remove(Object keyObject) {
        K key = (K) keyObject;
        boolean removed = containsKey(key);
        V oldValue = super.remove(key);
        if (removed)
            fireEntryRemoved(key, oldValue);
        return oldValue;
    }


    private void fireEntryAdded(K key, V value) {
        MapEvent<K, V> e = MapEvent.createEntryAddedEvent(this, key, value);
        for (MapListener<K, V> listener : listeners)
            listener.entryAdded(e);
    }


    private void fireEntryRemoved(K key, V value) {
        MapEvent<K, V> e = MapEvent.createEntryRemovedEvent(this, key, value);
        for (MapListener<K, V> listener : listeners)
            listener.entryRemoved(e);
    }


    private void fireValueChanged(K key, V oldValue, V newValue) {
        MapEvent<K, V> e = MapEvent.createValueChangedEvent(
                                                            this,
                                                            key,
                                                            oldValue,
                                                            newValue);
        for (MapListener<K, V> listener : listeners)
            listener.valueChanged(e);
    }


    public void addMapListener(MapListener<K, V> listener) {
        listeners.add(listener);
    }


    public void removeMapListener(MapListener<K, V> listener) {
        listeners.remove(listener);
    }
}
